home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 095 / tbbs105.arc / MAILSYS.INC < prev   
Text File  |  1985-10-02  |  17KB  |  657 lines

  1. const
  2.   numsects = 12;
  3.   maxlength = 24;
  4.   maxlenstr = '24';
  5.  
  6. type
  7.   messages = record
  8.               number:  integer;
  9.               sender:  integer;
  10.               recver:  integer;
  11.               subject: name;
  12.               date:    name;
  13.               private: boolean;
  14.               section: byte;
  15.               repto:   integer;
  16.               reply:   integer;
  17.               recved:  boolean;
  18.             end;
  19.   sectname = array[1..numsects] of string[20];
  20.   messtext = array[1..maxlength] of line;
  21.  
  22. const
  23.   sect : sectname = ('1: General',
  24.                      '2: Ohio Scientific',
  25.                      '3: CP/M',
  26.                      '4: Buy and Sell',
  27.                      '5: 6502',
  28.                      '6: Turbo Pascal',
  29.                      '7: C',
  30.                      '8: CompuServe',
  31.                      '9: 6809',
  32.                      '10: Kaypro',
  33.                      '11: MS-DOS',
  34.                      '12: TurboBBS code');
  35.  
  36.   maxmess = 52;   { <-- Maximum number of messages - this limit due to CP/M
  37.                     maximum directory size on Kaypro.}
  38.  
  39. var
  40.   messagefile: file of messages;
  41.   count: integer;
  42.   messtable: array[1..maxmess] of messages;
  43.   preformat: boolean;
  44.  
  45. function namemess(number: integer): name;
  46.  
  47.   var
  48.     filename: name;
  49.  
  50.   begin
  51.     str((10000 + number):6, filename);
  52.     namemess := messdrive + 'MESS' + copy(filename, 3, 4) + '.TXT';
  53.   end;
  54.  
  55. procedure kill(x: integer);
  56.  
  57.   var
  58.     victim: text;
  59.  
  60.   begin
  61.     assign(victim, namemess(x));
  62.     erase(victim);
  63.   end;
  64.  
  65. function secure(tabloc: byte): boolean;
  66.  
  67.   begin
  68.     with messtable[tabloc] do
  69.       secure := ((usernum <> sender)
  70.                 and (usernum <> recver)
  71.                 and (access < sysop))
  72.                 or (usernum = 0);
  73.   end;
  74.  
  75. procedure listsections;
  76.  
  77.   var
  78.     loopvar : integer;
  79.     temp    : line;
  80.  
  81.   begin
  82.     if cts then begin
  83.       clearsc;
  84.       lineout('Sections:' + cr + lf);
  85.       for loopvar := 1 to numsects do begin
  86.         lineout(sect[loopvar]);
  87.       end;
  88.     end;
  89.   end;
  90.  
  91. procedure status;
  92.  
  93.   var
  94.     temp: line;
  95.  
  96.   begin
  97.     if cts then begin
  98.       lineout(cr + lf + 'Caller: ' + caller);
  99.       str(access:1, temp);
  100.       lineout('Access level: ' + temp);
  101.       str(count:2, temp);
  102.       lineout('System has ' + temp + ' messages;');
  103.       str(nextmess:4, temp);
  104.       lineout('Next message is: ' + temp);
  105.     end;
  106.   end;
  107.  
  108. procedure initmess;
  109.  
  110.   begin
  111.     if cts then lineout(cr + lf + 'Initializing message system...');
  112.     count := 0;
  113.     nextmess := 1;
  114.     assign(messagefile, 'MESSAGES.BBS');
  115.     {$I-} reset(messagefile) {$I+};
  116.     if IOresult = 0 then begin
  117.       while (count < maxmess) and not eof(messagefile) do begin
  118.         count := count + 1;
  119.         read(messagefile, messtable[count]);
  120.       end;
  121.       close(messagefile);
  122.       if count > 0 then nextmess := messtable[count].number + 1;
  123.     end;
  124.     unload;
  125.     messopen := true;
  126.     status;
  127.   end;
  128.  
  129. function findmessage(x: integer): byte;
  130.  
  131.   var
  132.     loop: byte;
  133.  
  134.   begin
  135.     loop := 0;
  136.     findmessage := 0;
  137.     if count > 0 then begin
  138.       repeat
  139.         loop := loop + 1;
  140.       until (loop >= count) or (messtable[loop].number >= x);
  141.       if messtable[loop].number = x
  142.         then findmessage := loop
  143.         else findmessage := 0;
  144.     end;
  145.   end;
  146.  
  147. function getname(usernum: integer): person;
  148.  
  149.   var
  150.     tempid: sysid;
  151.  
  152.   begin
  153.     seek(idfile, usernum-1);
  154.     read(idfile, tempid);
  155.     getname := tempid.user;
  156.   end;
  157.  
  158. procedure header(tabloc: byte);
  159.  
  160.   var
  161.     temp: line;
  162.  
  163.   begin
  164.     if cts then with messtable[tabloc] do begin
  165.       str(number:4, temp);
  166.       stringout(cr + lf);
  167.       if private then stringout('Private ');
  168.       stringout('Message #' + temp);
  169.       temp := getname(sender);
  170.       stringout(' is from: ' + temp);
  171.       if recver > 0 then temp := getname(recver) else temp := 'ALL';
  172.       if recved then temp := temp + ' (Rec''d)';
  173.       lineout(' to: ' + temp);
  174.       stringout('Subj: ' + subject);
  175.       if clockin then stringout('  Time: ' + date);
  176.       if sectsin then stringout('  Section ' + sect[section]);
  177.       lineout(space);
  178.     end;
  179.   end;
  180.  
  181. procedure destroy(tabloc: byte);
  182.  
  183.   var
  184.     loop: byte;
  185.  
  186.   begin
  187.     if tabloc > 0 then begin
  188.       kill(messtable[tabloc].number);
  189.       for loop := tabloc+1 to count do
  190.         messtable[loop-1] := messtable[loop];
  191.       count := count - 1;
  192.       lineout('Message deleted.');
  193.     end;
  194.   end;
  195.  
  196. procedure readfile(tabloc: byte);
  197.  
  198.   begin
  199.     if cts then begin
  200.       outfile(namemess(messtable[tabloc].number));
  201.       lineout(space);
  202.       if (messtable[tabloc].recver = usernum) and (usernum > 0)
  203.         then messtable[tabloc].recved := true;
  204.       if cts and (tabloc > 1) and not secure(tabloc) then begin
  205.         if getcap('Delete (Y/N)? ') = 'Y' then destroy(tabloc);
  206.       end;
  207.     end;
  208.   end;
  209.  
  210. procedure readmess(number: integer);
  211.  
  212.   var tabloc: byte;
  213.  
  214.   begin
  215.     tabloc := findmessage(number);
  216.     if tabloc = 0 then lineout('Message not found.')
  217.       else if (secure(tabloc) and messtable[tabloc].private)
  218.         then lineout('Private message.')
  219.         else begin
  220.           header(tabloc);
  221.           readfile(tabloc);
  222.         end;
  223.   end;
  224.  
  225. procedure delmessage(x: integer);
  226.  
  227.   var
  228.     tabloc: byte;
  229.  
  230.   begin;
  231.     tabloc := findmessage(x);
  232.     if cts then begin
  233.       if tabloc > 0 then begin
  234.         if not secure(tabloc) then begin
  235.           header(tabloc);
  236.           if getcap('Are you sure (Y/N)? ') = 'Y' then destroy(tabloc);
  237.         end
  238.         else lineout('You can''t delete that message.');
  239.       end
  240.       else lineout('Message not found.');
  241.     end;
  242.   end;
  243.  
  244. function getid(prompt: line): integer;
  245.  
  246.   var
  247.     temp: person;
  248.  
  249.   begin
  250.     temp := allcaps(getinput(prompt, 28, echo));
  251.     if temp = '' then getid := 0 else getid := findid(temp);
  252.   end;
  253.  
  254. procedure deletex;
  255.  
  256.   begin
  257.     if cts then delmessage(getint(nextmess - 1, 0, 'Delete: which number? '));
  258.   end;
  259.  
  260. procedure quickscan;
  261.  
  262.   var
  263.     loop: byte;
  264.     first: integer;
  265.  
  266.   begin
  267.     if cts then begin
  268.       first := getint(nextmess - 1, lastmess + 1, 'Start scan at which number (* for new)? ');
  269.       if first > 0 then begin
  270.         clearsc;
  271.         for loop := 1 to count do
  272.           if (messtable[loop].number >= first)
  273.             and not (secure(loop) and messtable[loop].private)
  274.             and cts and not cancelled
  275.             then header(loop);
  276.       end;
  277.     end;
  278.   end;
  279.  
  280. procedure readind;
  281.  
  282.   var
  283.    messnum: integer;
  284.    tabloc : byte;
  285.  
  286.   begin
  287.     repeat
  288.       messnum := getint(nextmess - 1, 0, 'Read which number (enter 0 to quit)? ');
  289.       if messnum > 0 then readmess(messnum);
  290.     until (messnum <= 0) or not cts;
  291.   end;
  292.  
  293. procedure messagesearch(first:byte; fromnum, tonum:integer; sectnum:byte);
  294.  
  295.   var
  296.     loop: byte;
  297.     inch: char;
  298.     oldnum: integer;
  299.     matched: boolean;
  300.  
  301.   begin
  302.     matched := false;
  303.     inch := null;
  304.     loop := first;
  305.     if loop = 0 then loop := 1;
  306.     while cts and (loop <= count) and (inch <> 'Q') and (count <> 0) do begin
  307.       oldnum := messtable[loop].number;
  308.       if ((fromnum = 0) or (fromnum = messtable[loop].sender))
  309.         and ((tonum = 0) or (tonum = messtable[loop].recver))
  310.         and ((sectnum = 0) or (sectnum = messtable[loop].section))
  311.         and not (secure(loop) and messtable[loop].private)
  312.       then begin
  313.         matched := true;
  314.         cancelled := false;
  315.         header(loop);
  316.         inch := getcap('Read (Y/N/Quit)? ');
  317.         if inch = 'Y' then readfile(loop);
  318.       end;
  319.       if messtable[loop].number = oldnum then loop := loop + 1;
  320.     end;
  321.     if cts and not matched then lineout('No messages found.');
  322.   end;
  323.  
  324. function findfirst(startmess: integer): byte;
  325.  
  326.   var loop : byte;
  327.  
  328.   begin
  329.     loop := 0;
  330.     if count > 0 then repeat
  331.       loop := loop + 1;
  332.     until (messtable[loop].number >= startmess) or (loop = count);
  333.     findfirst := loop;
  334.   end;
  335.  
  336. function getfirst: byte;
  337.  
  338.   var
  339.     startmess : integer;
  340.  
  341.   begin
  342.     repeat
  343.       startmess := getint(nextmess - 1, lastmess + 1, 'Start at which message (? for stats, * for new)? ');
  344.       if startmess = -1 then status;
  345.     until (startmess <> -1) or not cts;
  346.     if startmess = 0 then getfirst := 0
  347.       else getfirst := findfirst(startmess);
  348.   end;
  349.  
  350. procedure readfrom;
  351.  
  352.   var
  353.     fromnum: integer;
  354.     first: byte;
  355.  
  356.   begin
  357.     if cts then begin
  358.       fromnum := getid('Enter name of sender: ');
  359.       if fromnum < 1
  360.         then stringout('Not a registered user name.')
  361.         else begin
  362.           first := getfirst;
  363.           if first > 0 then messagesearch(first, fromnum, 0, 0);
  364.         end;
  365.     end;
  366.   end;
  367.  
  368. procedure readto;
  369.  
  370.   var
  371.     tonum: integer;
  372.     first: byte;
  373.  
  374.   begin
  375.     if cts then begin
  376.       tonum := getid('Enter name of addressee: ');
  377.       if tonum < 1
  378.         then stringout('Not a registered user name.')
  379.         else begin
  380.           first := getfirst;
  381.           if first > 0 then messagesearch(first, 0, tonum, 0);
  382.         end;
  383.     end;
  384.   end;
  385.  
  386. procedure readsect;
  387.  
  388.   var
  389.     first: byte;
  390.     inch: integer;
  391.  
  392.   begin
  393.     if cts then repeat
  394.       if sectsin then
  395.         inch := getint(numsects, 0, 'Enter section number (0 for all, ? for list): ')
  396.         else inch := 1;
  397.       case inch of
  398.         -1          : listsections;
  399.          0..numsects: begin
  400.                          first := getfirst;
  401.                          if first > 0 then messagesearch(first, 0, 0, inch);
  402.                        end;
  403.       end;
  404.     until (inch <> -1) or not cts;
  405.   end;
  406.  
  407. procedure receive;
  408.  
  409.   var
  410.     uchar: char;
  411.  
  412.   begin
  413.     if cts then begin
  414.       clearsc;
  415.       if not expert then outfile(readmenu);
  416.       repeat
  417.         uchar := getcap('Read mode: (A,I,F,T,S, or ? for menu)? ');
  418.         if uchar = '?' then outfile(readmenu);
  419.       until (uchar in ['A','I','F','T','S',cr]) or not cts;
  420.       if uchar = 'I' then readind;
  421.       if cts and (uchar <> 'I') then begin
  422.         case uchar of
  423.           'A': messagesearch(getfirst,0,0,0);
  424.           'F': readfrom;
  425.           'T': readto;
  426.           'S': readsect;
  427.         end;
  428.       end;
  429.     end;
  430.   end;
  431.  
  432. procedure closemess;
  433.  
  434.   var
  435.     loop: byte;
  436.  
  437.   begin
  438.     rewrite(messagefile);
  439.     for loop := 1 to count do
  440.       write(messagefile, messtable[loop]);
  441.     close(messagefile);
  442.     messopen := false;
  443.   end;
  444.  
  445. {make "enter" an overlay procedure and make filesys another one to save space}
  446. procedure enter;
  447.  
  448.   var
  449.     tabloc: byte;
  450.     messbuff: messtext;
  451.     linenum: byte;
  452.     inch: char;
  453.  
  454.   procedure compose(var block: messtext; var linenum: byte);
  455.  
  456.     var
  457.       temp: name;
  458.  
  459.     begin
  460.       lineout(cr + lf + 'Enter message text: ' + maxlenstr + ' lines of 80 chars max.');
  461.       lineout('An empty line ends entry. "." at start of line forces new line.');
  462.       lineout(space);
  463.       if linenum < maxlength then repeat
  464.         linenum := linenum + 1;
  465.         str(linenum:2, temp);
  466.         stringout(temp + ': ');
  467.         block[linenum] := inputstring(echo);
  468.       until (linenum = maxlength) or (block[linenum] = '') or not cts;
  469.       if block[linenum] = '' then linenum := linenum - 1;
  470.     end;
  471.  
  472.   procedure list(var block: messtext; first, last: byte);
  473.  
  474.     var
  475.       loop: byte;
  476.       temp: name;
  477.  
  478.     begin
  479.       if (first > 0) and (last > 0) and cts then begin
  480.         loop := first;
  481.         while (loop <= last) and (not cancelled) and cts do begin
  482.           str(loop:2, temp);
  483.           stringout(temp + ': ');
  484.           lineout(block[loop]);
  485.           loop := loop + 1;
  486.         end;
  487.         lineout(space);
  488.       end;
  489.     end;
  490.  
  491.   procedure delline(var block: messtext; linenum: byte; var maxline: byte);
  492.  
  493.     var temp: char;
  494.         loop: byte;
  495.  
  496.     begin
  497.       list(block, linenum, linenum);
  498.       if cts and (linenum > 0) then begin
  499.         temp := getcap('Delete: are you sure (Y/N)? ');
  500.         if temp = 'Y' then begin
  501.           for loop := linenum+1 to maxline do block[loop-1] := block[loop];
  502.           block[maxline] := '';
  503.           maxline := pred(maxline);
  504.           lineout('Line deleted.');
  505.         end;
  506.       end;
  507.     end;
  508.  
  509.   procedure edit(var block: messtext; linenum: byte);
  510.  
  511.     var
  512.       oldstring: line;
  513.       newstring: line;
  514.       posn     : integer;
  515.  
  516.     begin
  517.       if (linenum > 0) and cts then begin
  518.         list(block, linenum, linenum);
  519.         oldstring := getinput('Enter string to replace: ', 80, echo);
  520.         newstring := getinput('Enter replacement: ', 80, echo);
  521.         posn := pos(oldstring, block[linenum]);
  522.         if posn <> 0 then begin
  523.           delete(block[linenum], posn, length(oldstring));
  524.           insert(newstring, block[linenum], posn);
  525.           list(block, linenum, linenum);
  526.         end
  527.         else lineout('Old string not found.');
  528.         lineout(space);
  529.       end;
  530.     end;
  531.  
  532.   procedure replace(var block: messtext; linenum: byte);
  533.  
  534.     begin
  535.       if (linenum > 0) and cts then begin
  536.         lineout('Old line:');
  537.         list(block, linenum, linenum);
  538.         lineout('Enter new line:');
  539.         stringout('? ');
  540.         block[linenum] := inputstring(echo);
  541.       end;
  542.     end;
  543.  
  544.   function whichline(linenum: byte): byte;
  545.  
  546.     var
  547.       temp: name;
  548.       x   : integer;
  549.  
  550.     begin
  551.       str(linenum:2, temp);
  552.       x := getint(linenum, 0, ' Which line? (1 - ' + temp + ')? ');
  553.       if (x <= 0) or not cts then whichline := 0 else whichline := x;
  554.     end;
  555.  
  556.   procedure newheader(var entry: messages);
  557.  
  558.     var
  559.       temp, tonum: integer;
  560.  
  561.     begin
  562.       if cts then begin
  563.         entry.sender := usernum;
  564.         tonum := getid('Who to (RETURN or ENTER key for ALL)? ');
  565.         if tonum = 0 then lineout('Message to: ALL');
  566.         entry.recver := tonum;
  567.         entry.subject := getinput('Subject (14 characters max.)? ', 14, echo);
  568.         if clockin then begin
  569.           clock(month, date, hour, min, sec);
  570.           entry.date := time(month, date, hour, min, sec);
  571.         end;
  572.         if sectsin then repeat
  573.           temp := getint(numsects, 0, 'Which section (or "?" for list)? ');
  574.           if temp = -1 then listsections;
  575.           if temp in [1..numsects] then entry.section := temp;
  576.         until (temp in  [1..numsects]) or not cts
  577.         else entry.section := 1;
  578.         if tonum > 0 then entry.private := getcap('Private message (Y/N)? ')='Y'
  579.         else entry.private := false;
  580.         entry.reply := 0;
  581.         entry.repto := 0;
  582.         entry.number := nextmess;
  583.         entry.recved := false;
  584.       end;
  585.     end;
  586.  
  587.   procedure storemess(var block: messtext; tabloc, lastline: byte);
  588.  
  589.     var
  590.       outfile: text;
  591.       linenum: byte;
  592.  
  593.     begin
  594.       if cts then begin
  595.         lineout('Writing message to disk...');
  596.         assign(outfile, namemess(nextmess));
  597.         rewrite(outfile);
  598.         linenum := 1;
  599.         while linenum <= lastline do begin
  600.           if (copy(block[linenum],1,1) = '.') or preformat then begin
  601.             writeln(outfile);
  602.             if not preformat then
  603.               block[linenum] := copy(block[linenum], 2, length(block[linenum])-1);
  604.           end
  605.           else write(outfile, ' ');
  606.           write(outfile, block[linenum]);
  607.           linenum := linenum + 1;
  608.         end;
  609.         writeln(outfile);
  610.         close(outfile);
  611.         unload;
  612.         nextmess := nextmess + 1;
  613.         count := count + 1;
  614.       end;
  615.     end;
  616.  
  617.   begin
  618.     preformat := false;
  619.     if cts then begin
  620.       clearsc;
  621.       if access < reg then lineout('You cannot enter messages yet: Use [A]pply command.')
  622.       else begin
  623.         tabloc := count + 1;
  624.         if tabloc > maxmess then lineout('No message space left.')
  625.         else begin
  626.           repeat
  627.             newheader(messtable[tabloc]);
  628.             header(tabloc);
  629.             inch := getcap('Is this OK (Y/N/Abort)? ');
  630.           until (inch <> 'N') or not cts;
  631.           unload;
  632.           if inch <> 'A' then begin
  633.             linenum := 0;
  634.             compose(messbuff, linenum);
  635.             if not expert then outfile(editmenu);
  636.             repeat
  637.               inch := getcap('Edit command: A,C,D,E,L,P,R,S or ? for menu? ');
  638.               case inch of
  639.                 'C': compose(messbuff, linenum);
  640.                 'D': delline(messbuff, whichline(linenum), linenum);
  641.                 'E': edit(messbuff, whichline(linenum));
  642.                 'L': list(messbuff, whichline(linenum), linenum);
  643.                 'P': begin preformat := true; storemess(messbuff, tabloc, linenum); end;
  644.                 'R': replace(messbuff, whichline(linenum));
  645.                 'S': storemess(messbuff, tabloc, linenum);
  646.                 '?': outfile(editmenu);
  647.               end;
  648.             until (inch = 'A')
  649.                or (inch = 'S')
  650.                or (inch = 'P')
  651.                or not cts;
  652.           end;
  653.         end;  {2nd else}
  654.       end;  {1st else}
  655.     end; {if cts}
  656.   end; {enter}
  657.